#include <QBuffer>
#include <QImageReader>
#include <QImage>
#include <QThread>
#include <QIODevice>
#include <QMutex>

#include "tcpsession.h"
#include "pack.h"

TcpSession* TcpSession::instance=nullptr;
QMutex TcpSession::mutex;

TcpSession* TcpSession::getInstance(const QString &hostname, const int &port, QObject *parent)
{
    if(instance != nullptr)
        return instance;
    mutex.lock();
    if(instance == nullptr){
        QTcpSocket* socket = new QTcpSocket();
        socket->connectToHost(hostname, port);
        instance=new TcpSession(socket, parent);
        instance->hostname=hostname;
        instance->port=port;
        QObject::connect(socket, &QTcpSocket::readyRead, instance, &TcpSession::onReadyRead);
        QObject::connect(socket, &QTcpSocket::disconnected, instance, &TcpSession::onDisconnected);
    }
    mutex.unlock();
    return instance;
}

TcpSession::TcpSession(QTcpSocket* socket,QObject *parent) :QObject(parent),socket(socket)
{
    QObject::connect(socket, &QTcpSocket::readyRead, this, &TcpSession::readyRead);
    QObject::connect(socket, &QTcpSocket::disconnected, this, &TcpSession::disconnected);
}

TcpSession::~TcpSession()
{
    if(socket != nullptr && socket->isOpen()){
        socket->disconnectFromHost();
    }
}

void TcpSession::clearSessionInfo()
{
    sessionMap.clear();
}

void TcpSession::readPacks()
{
    while(1){
        if(packsize == 0){
            if(socket->bytesAvailable() < 4){
                return;
            }
            socket->read((char*)&packsize, 4);
        }
        if(socket->bytesAvailable() < packsize-4)
            return;
        Pack pack;
        pack.setPacksize(packsize);
        int cnt=4;//packsize已经读取过了
        //类型
        socket->read((char*)&pack+cnt, 4);
        cnt+=4;

        //返回值
        socket->read((char*)&pack+cnt, 4);
        cnt+=4;

        //视频流和摄像头数据流不处理
        if(pack.getType() == VIDEO || pack.getType() == CAMERA){
            socket->read((char*)&pack+cnt, pack.getPacksize()-cnt);
            //本报读完
            vector.append(pack);
            packsize=0;
            continue;
        }

        //char[4096]的内容
        QStringList list;
        while(cnt < packsize){
            //字段长度
            socket->read((char*)&pack+cnt, 2);
            unsigned short len=0;
            memcpy(&len,(char*)&pack+cnt,2);
            cnt+=2;

            //字段内容
            socket->read((char*)&pack+cnt, len);
            QString str=QString::fromLocal8Bit((char*)&pack+cnt, len);
            cnt+=len;
            //
            list.append(str);
        }
        pack.setFieldList(list);
        //本报读完
        vector.append(pack);
        packsize=0;
    }
}


Pack TcpSession::popFrontPack()
{
    Pack pack=vector.front();
    vector.pop_front();
    return pack;
}

int TcpSession::send(char *buf, int buflen)
{
    if(socket->state()!=QAbstractSocket::ConnectedState){
        while(1){
            socket->connectToHost(hostname, port);
            if(socket->waitForConnected()){
                QObject::connect(socket, &QTcpSocket::readyRead, this, &TcpSession::onReadyRead);
                QObject::connect(socket, &QTcpSocket::disconnected, this, &TcpSession::onDisconnected);
                break;
            }
        }
    }
    return socket->write(buf, buflen);
}

void TcpSession::putValue(const QString & key, const QString & value)
{
    sessionMap.insert(key, value);
}

QString TcpSession::getValue(const QString &key)
{
    if(!sessionMap.contains(key))
        return "";
    return sessionMap.find(key).value();
}

void TcpSession::onReadyRead()
{
    //解析
    readPacks();
    int vecsize=getVectorSize();
    for(int i=0;i<vecsize;i++){
        Pack retPack=popFrontPack();

        //登录-回复报文
        if(retPack.getType() == LOGIN){
            if("SUCCESS" == retPack.getFieldList()[0]){
                QString username=retPack.getFieldList()[1];
                QString nickname=retPack.getFieldList()[2];
                //
                emit login_ret_signal(true, username, nickname);
                continue;
            }
            QString errmsg=retPack.getFieldList()[1];
            emit login_ret_signal(false, errmsg);
            continue;
        }
        //注册-回复报文
        if(retPack.getType() == REGIST){
            QString res=retPack.getFieldList()[0];
            if(res == "SUCCESS"){
                emit reg_ret_signal(true);
                continue;
            }
            emit reg_ret_signal(false, retPack.getFieldList()[1]);
            continue;
        }
        //查询直播间列表-回复报文
        if(retPack.getType()==HOUSE_LIST){
            //刷新表格
            QStringList& fields=retPack.getFieldList();
            //
            emit houselist_ret_signal(fields);
            continue;
        }
        //登出
        if(retPack.getType()==LOGOUT){
            emit logout_call_signal(retPack.getFieldList()[0]);
            continue;
        }
        //创建房间返回报文
        if(retPack.getType()==HOUSE_ADD){
            QStringList fields=retPack.getFieldList();
            if(fields[0] == "SUCCESS"){
                emit house_add_signal(true);
                continue;
            }
            emit house_add_signal(false, fields[1]);
            continue;
        }
        //房间成员列表
        if(retPack.getType()==HOUSE_MEMS){
            emit houseMems_signal(retPack.getFieldList());
            continue;
        }
        //房间的实时消息
        if(retPack.getType()==HOUSE_MSG){
            emit houseMsg_signal(retPack.getFieldList()[0]);
            continue;
        }
        //视频流
        if(retPack.getType() == VIDEO){
            int houseid2;
            int pixid2;
            int total2;
            int packno2;
            int bufCnt;
            //videoByteArr
            int cntBuf=12;
            //
            memcpy(&houseid2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&pixid2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&total2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&packno2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&bufCnt, (char*)&retPack+cntBuf,4);
            cntBuf+=4;

            if(packno2==0){//新的图片的第一张
                videoByteArr.clear();
            }
            videoByteArr.append((char*)&retPack+cntBuf, bufCnt);
            if(packno2==total2-1){//一张图片的最后一包
                QBuffer buf(&videoByteArr);
                QImageReader reader(&buf,"jpg");
                QImage image = reader.read();
                //
                emit video_signal(image);
            }
            continue;
        }

        //摄像头
        if(retPack.getType() == CAMERA){
            int houseid2;
            int pixid2;
            int total2;
            int packno2;
            int bufCnt;
            //videoByteArr
            int cntBuf=12;
            //
            memcpy(&houseid2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&pixid2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&total2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&packno2, (char*)&retPack+cntBuf,4);
            cntBuf+=4;
            //
            memcpy(&bufCnt, (char*)&retPack+cntBuf,4);
            cntBuf+=4;

            if(packno2==0){//新的图片的第一张
                cameraByteArr.clear();
            }
            cameraByteArr.append((char*)&retPack+cntBuf, bufCnt);
            if(packno2==total2-1){//一张图片的最后一包
                QBuffer buf(&cameraByteArr);
                QImageReader reader(&buf,"jpg");
                QImage image = reader.read();
                //
                emit camera_signal(image);
            }
            continue;
        }

        if(retPack.getType() == GIFT){
            //
            QStringList fields=retPack.getFieldList();
            emit gift_signal(fields[1], fields[2], fields[3]);
            continue;
        }
        if(retPack.getType() == BULLET){
            QStringList fields=retPack.getFieldList();
            emit bullet_signal(fields[1],fields[2], fields[3]);
            continue;
        }
        if(retPack.getType() == HOUSE_ENTER){
            QStringList fields=retPack.getFieldList();
            if("SUCCESS" == fields[0]){
                emit house_enter_signal(true);
                continue;
            }
            emit house_enter_signal(false,fields[1]);
            continue;
        }


        //此处继续添加代码
        qDebug() << "TcpSession::onReadyRead: 收到不支持的报文类型 type"<<retPack.getType()<<", frame="<<retPack
                    .getFrame();
        continue;
    }


}

void TcpSession::onDisconnected()
{
    emit logout_call_signal("TCP连接异常断开，程序即将退出");
//    while(1){
//        socket->connectToHost(hostname, port);
//        if(socket->waitForConnected()){
//            QObject::connect(socket, &QTcpSocket::readyRead, this, &TcpSession::onReadyRead);
//            QObject::connect(socket, &QTcpSocket::disconnected, this, &TcpSession::onDisconnected);
//            break;
//        }
//    }
}
